<?php

namespace app\caches;

use app\commons\SingleInstanceTrait;
use support\Cache;

/**
 * 缓存基类
 * 我们通常创建子类，继承 CacheBase，然后定义他的前缀prefix 和实现获取真实数据的方法getReal 即可
 * 在外部调用缓存时，访问接口 remember($key='') 即可。这样会去寻找缓存内容，如果找不到则去拉去真实数据回来放入缓存。
 * eg: $game = GameCache::getInstance()->remember(1001);
 *
 * 如果我们需要清理掉某个缓存，则调用 forget($key='')
 * 如果我们需要清理此子类下的所有缓存，则调用 flush()
 */
class CacheBase
{
    use SingleInstanceTrait;

    /**
     * 缓存前缀
     * @var string
     */
    protected $prefix;

    /**
     * 缓存多少分钟 永久使用字符串 forever 默认缓存 7天
     * @var string|int
     */
    protected $minutes = 10080;

    /**
     * 读取缓存唯一key
     * @param  string|array  $key    检索key
     * @return string
     */
    private function getUnid($key)
    {
        if (is_array($key)) {
            ksort($key);
            $unid = $this->prefix . ':' . http_build_query($key);
        } else {
            $unid = $this->prefix . ':' . $key;
        }

        return $unid;
    }

    /**
     * 是否存在某缓存
     * @param  string         $key       检索key
     * @return boolean
     */
    public function has($key='')
    {
        $unid = $this->getUnid($key);
        if (!Cache::has($unid)) {
            return false;
        }

        return true;
    }

    /**
     * 更新缓存数据
     *
     * @param string $key
     * @param mixed $value
     * @return boolean
     */
    public function update($key, $value)
    {
        $unid = $this->getUnid($key);
        $minutes = $this->minutes;

        // 此处采用伪永久缓存，缓存时长为10年
        if ($minutes == 'forever') {
            $minutes = 5256000;
        }

        $second = intval($minutes*60);
        return Cache::set($unid, $value, $second);
    }

    /**
     * 读取缓存数据
     *
     * @param string $key
     * @return void
     */
    public function get($key='')
    {
        $unid = $this->getUnid($key);
        return Cache::get($unid);
    }

    /**
     * 记忆读取缓存数据
     * @param  string $key 检索key
     * @return mixed
     */
    public function remember($key='')
    {
        $value = $this->get($key);
        if (!$value) {
            $value = call_user_func(array($this, 'getReal'), $key);
            if (!$value) return;
            $this->update($key, $value);
        }

        return $value;
    }

    /**
     * 读取真实数据，此接口只能由 remember 来回调
     * @param  string|array  $key    检索key
     * @return mixed
     */
    protected function getReal($key = '')
    {
        //
    }

    // 从缓存中移除一项
    public function forget($key='')
    {
        $unid = $this->getUnid($key);
        return Cache::delete($unid);
    }
}
